﻿using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Modules.Constants;
using System.Modules.SharePoint.Contracts.Enums;
using System.Modules.SharePoint.Extensions;
using System.Modules.Utility.DTO;
using System.Windows.Forms;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using System.Modules.SharePoint.Contracts.DTO;
using System.Collections;

namespace System.Modules.Utility
{
    public partial class MainForm : Form
    {
        #region Constructor
        public MainForm()
        {
            InitializeComponent();
        }
        #endregion

        #region Event Handlers
        private void btnBindApplications_Click(object sender, EventArgs e)
        {
            if (btnBindApplications.Tag == null)
            {
                btnBindApplications.Tag = new BackgroundWorker { WorkerSupportsCancellation = true, WorkerReportsProgress = true };
            }
            Execute(btnBindApplications, btnBindApplications.Tag as BackgroundWorker, BindApplications, BindApplicationsCompleted);
        }

        private void CbWebApplicationsSelectedIndexChanged(object sender, EventArgs e)
        {
            var cb = sender as ComboBox;
            if (cb != null)
            {
                var wa = cb.SelectedItem as SPWebApplication;
                if (wa != null)
                {
                    cbSites.DataSource = wa.Sites.ToList();
                }
            }
        }

        private void TxtWebUrlDoubleClick(object sender, EventArgs e)
        {
            using (var lookup = new WebLookup(SiteUrl))
            {
                lookup.ShowDialog(owner: this);
            }
        }

        private void btnTest_Click(object sender, EventArgs e)
        {
            var query = new Query();
            query.SiteUrl = SiteUrl;
            query.WebUrl = WebUrl;
            query.ListName = ListName;
            if (btnTest.Tag == null)
            {
                btnTest.Tag = new BackgroundWorker { WorkerSupportsCancellation = true, WorkerReportsProgress = true };
            }
            Execute(btnTest, btnTest.Tag as BackgroundWorker, Test, TestCompleted, query);
        }

        private void btnGetPropertyBagItems_Click(object sender, EventArgs e)
        {
            var query = new Query();
            query.SiteUrl = SiteUrl;
            query.WebUrl = WebUrl;
            query.ListName = ListName;
            if (btnGetPropertyBagItems.Tag == null)
            {
                btnGetPropertyBagItems.Tag = new BackgroundWorker { WorkerSupportsCancellation = true, WorkerReportsProgress = true };
            }
            Execute(btnGetPropertyBagItems, btnGetPropertyBagItems.Tag as BackgroundWorker, GetPropertyBagItems, GetPropertyBagItemsCompleted, query);
        }
        #endregion

        #region Handlers
        public void BindApplications(object sender, DoWorkEventArgs e)
        {
            if (SPWebService.ContentService != null)
            {
                e.Result = SPWebService.ContentService.WebApplications;
            }
        }
        public void BindApplicationsCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                if (e.Result != null)
                {
                    var collection = e.Result as SPWebApplicationCollection;
                    if (collection != null)
                    {
                        cbWebApplications.DataSource = collection.ToList();
                    }
                }
            }
            else
            {
                LogException(e.Error);
            }
            pb.Style = ProgressBarStyle.Blocks;
        }
        public void Test(object sender, DoWorkEventArgs e)
        {
            LogDistinctMessage = string.Empty;
            var query = e.Argument as Query;
            if (query != null)
            {
                using (var site = new SPSite("https://tamkeentest.eaa.ae/"))
                {
                    using (var web = site.OpenWeb("/Document Center/"))
                    {
                        var spQuery = new SPSiteDataQueryBuilder();
                        spQuery.Lists.BaseType = SPListBaseType.DocumentLibrary;
                        spQuery.Lists.ServerTemplate = SPListServerTemplate.DocumentLibrary;
                        spQuery.Lists.MaxListLimit = 0;
                        spQuery.Webs = SPQueryWebsScope.Recursive;
                        spQuery.Query.Condition = new SPQueryIsNotNullOperation("_vti_ItemDeclaredRecord");
                        spQuery.QueryThrottleMode = SPQueryThrottleOption.Default;
                        var dt = web.GetSiteData(spQuery.ToQuery());
                        LogDistinctMessage = dt.Rows.Count.ToString();
                        //var list = web.Lists.TryGetList("Calendar");
                        //if (list != null)
                        //{
                        //    string startDate = SPUtility.CreateISO8601DateTimeFromSystemDateTime(new DateTime(2013, 5, 1));
                        //    string endDate = SPUtility.CreateISO8601DateTimeFromSystemDateTime(new DateTime(2013, 5, 31));
                        //    var queryBuilder = new SPQueryBuilder();
                        //    //queryBuilder.Condition = new SPQueryOperation("EventDate", startDate, SPFieldType.DateTime, SPQueryCamlOperation.Geq);
                        //    //queryBuilder.And(new SPQueryOperation("EndDate", endDate, SPFieldType.DateTime, SPQueryCamlOperation.Leq));
                        //    //queryBuilder.OrderBy("EventDate", Web.UI.WebControls.SortDirection.Ascending);
                        //    queryBuilder.Condition = new SPQueryRecurrenceBuilder(SPQueryCamlDateValues.Month);
                        //    queryBuilder.CalendarDate = new DateTime(2013, 6, 1);
                        //    queryBuilder.ExpandRecurrence = true;
                        //    SPQuery spQuery = queryBuilder;
                        //    LogDistinctMessage = spQuery.Query;
                        //    e.Result = list.GetItems(spQuery);
                        //}
                    }
                }
            }
        }
        public void TestCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                var items = e.Result as SPListItemCollection;
                if (items != null)
                {
                    LogDistinctMessage = items.Count.ToString(CultureInfo.InvariantCulture);
                    foreach (SPListItem item in items)
                    {
                        LogDistinctMessage = item.LoadItem<EventListItem>().ToString();
                    }
                }
            }
            else
            {
                LogException(e.Error);
            }
        }
        public void GetPropertyBagItems(object sender, DoWorkEventArgs e)
        {
            LogDistinctMessage = string.Empty;
            var query = e.Argument as Query;
            if (query != null)
            {
                using (var site = new SPSite("https://eaaportaltest.eaa.ae/"))
                {
                    using (var web = site.OpenWeb("/TEST/"))
                    {
                        var list = web.Lists.TryGetList("Custom");
                        if (list != null)
                        {
                            e.Result = list.RootFolder.Properties;
                        }
                    }
                }
            }
        }
        public void GetPropertyBagItemsCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                var items = e.Result as Hashtable;
                if (items != null)
                {
                    LogDistinctMessage = items.Count.ToString(CultureInfo.InvariantCulture);
                    foreach (DictionaryEntry item in items)
                    {
                        LogDistinctMessage = string.Format("Key: {0} | Value: {1}", item.Key, item.Value);
                    }
                }
            }
            else
            {
                LogException(e.Error);
            }
        }
        #endregion

        #region Methods
        void Execute(ToolStripButton btn, BackgroundWorker worker, DoWorkEventHandler workerDoWork, RunWorkerCompletedEventHandler workerRunWorkerCompleted, Query arguments = null)
        {
            Execute(btn, worker, workerDoWork, workerRunWorkerCompleted, null, arguments);
        }
        void Execute(ToolStripButton btn, BackgroundWorker worker, DoWorkEventHandler workerDoWork, RunWorkerCompletedEventHandler workerRunWorkerCompleted, ProgressChangedEventHandler workerProgressChanged, Query arguments)
        {
            if (worker.IsBusy)
            {
                if (worker.WorkerSupportsCancellation)
                {
                    btn.Enabled = false;
                    worker.CancelAsync();
                }
            }
            else
            {
                if (arguments == null) { arguments = new Query(); }
                worker.DoWork -= DoWork;
                worker.DoWork += DoWork;
                if (!worker.CancellationPending)
                {
                    worker.DoWork -= workerDoWork;
                    worker.DoWork += workerDoWork;
                }
                worker.RunWorkerCompleted -= RunWorkerCompleted;
                worker.RunWorkerCompleted += RunWorkerCompleted;
                worker.RunWorkerCompleted -= workerRunWorkerCompleted;
                worker.RunWorkerCompleted += workerRunWorkerCompleted;
                RunWorkerCompletedEventHandler invoker = delegate
                                                         {
                                                             btn.DisplayStyle = ToolStripItemDisplayStyle.Text;
                                                             btn.Enabled = true;
                                                         };
                worker.RunWorkerCompleted -= invoker;
                worker.RunWorkerCompleted += invoker;
                if (worker.WorkerReportsProgress)
                {
                    worker.ProgressChanged -= ProgressChanged;
                    worker.ProgressChanged += ProgressChanged;
                    if (workerProgressChanged != null)
                    {
                        worker.ProgressChanged -= workerProgressChanged;
                        worker.ProgressChanged += workerProgressChanged;
                    }
                }
                arguments.SiteUrl = SiteUrl;
                arguments.WebUrl = WebUrl;
                btn.DisplayStyle = ToolStripItemDisplayStyle.ImageAndText;
                ProcessStartDate = DateTime.Now;
                ProcessEndDate = new DateTime?();
                worker.RunWorkerAsync(arguments);
            }
        }
        void DoWork(object sender, DoWorkEventArgs e)
        {
            LogMessage = string.Empty;
            ExceptionCounter = 0;
            var worker = sender as BackgroundWorker;
            if (worker != null)
            {
                if (CheckWorkerCancellationStatus(sender, e)) { }
            }
        }
        bool CheckWorkerCancellationStatus(object sender, DoWorkEventArgs e)
        {
            var worker = sender as BackgroundWorker;
            if (worker != null)
            {
                if (worker.CancellationPending)
                {
                    e.Cancel = worker.CancellationPending;
                }
            }
            return e.Cancel;
        }
        void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            LogException(e.Error);
            if (e.Cancelled)
            {
                LogMessage = "Process Cancelled";
            }
            else
            {
                LogMessage = "Process Completed Successfully";
            }
            ProcessEndDate = DateTime.Now;
            ElapsedDateTime = ProcessTimeSpan;
            LogMessage = txtElapsedDateTime.Text;
            LogMessage = txtExceptionsOccurred.Text;
        }
        void ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            lblMessage.Text = String.Format("Progress: {0}", _totalRecords == 0 ? e.ProgressPercentage.ToString(CultureInfo.InvariantCulture) : String.Format("{0} out of {1}", e.ProgressPercentage, _totalRecords));
            if (e.UserState != null)
            {
                LogMessage = e.UserState.ToString();
            }
            ProcessEndDate = DateTime.Now;
            ElapsedDateTime = ProcessTimeSpan;
        }
        void LogException(Exception exception)
        {
            LogException(exception, false);
        }
        void LogException(Exception exception, bool isRecursive)
        {
            if (exception != null)
            {
                if (!isRecursive)
                {
                    ExceptionCounter++;
                    //txtExceptionsOccurred.Text = String.Format("Exceptions Occured: {0}", ++_ExceptionCounter);
                }
                LogError = exception.Message;
                LogError = exception.StackTrace;
                LogException(exception.InnerException, isRecursive);
            }
        }
        #endregion

        #region Properties
        TextBox CurrentLogTextBox
        {
            get
            {
                TextBox value = null;
                MethodInvoker invoker = () => { value = tabControl.SelectedTab.Controls.Cast<Control>().FirstOrDefault(match => match.Name.StartsWith("txtLog", StringComparison.CurrentCultureIgnoreCase)) as TextBox; };
                if (tabControl.InvokeRequired)
                {
                    tabControl.Invoke(invoker);
                }
                else
                {
                    invoker.Invoke();
                }
                return value;
            }
        }
        String LogDistinctMessage
        {
            set
            {
                MethodInvoker invoker;
                var txtCurrentLog = CurrentLogTextBox ?? txtLog;
                if (string.IsNullOrEmpty(value))
                {
                    invoker = () => txtCurrentLog.Clear();
                }
                else
                {
                    invoker = () => txtCurrentLog.AppendText(String.Format("{0} : MSG : {1} \r\n", DateTime.Now, value));
                }
                if (txtCurrentLog.InvokeRequired)
                {
                    txtCurrentLog.Invoke(invoker);
                }
                else
                {
                    invoker.Invoke();
                }
            }
        }
        String LogMessage
        {
            set
            {
                MethodInvoker invoker;
                if (string.IsNullOrEmpty(value))
                {
                    invoker = () => txtLog.Clear();
                }
                else
                {
                    invoker = () => txtLog.AppendText(String.Format("{0} : MSG : {1} \r\n", DateTime.Now, value));
                }
                if (txtLog.InvokeRequired)
                {
                    txtLog.Invoke(invoker);
                }
                else
                {
                    invoker.Invoke();
                }
            }
        }
        String LogError
        {
            set
            {
                MethodInvoker invoker = null;
                if (!string.IsNullOrEmpty(value))
                {
                    invoker = () => txtLog.AppendText(String.Format("{0} : ERR : {1} \r\n", DateTime.Now, value));
                }
                if (invoker != null)
                {
                    if (txtLog.InvokeRequired)
                    {
                        txtLog.Invoke(invoker);
                    }
                    else
                    {
                        invoker.Invoke();
                    }
                }
            }
        }
        String SiteUrl
        {
            get
            {
                var site = cbSites.SelectedItem as SPSite;
                return site != null ? site.Url : cbSites.Text;
            }
        }
        public String WebUrl
        {
            private get
            {
                return txtWebUrl.Text;
            }
            set
            {
                txtWebUrl.Text = value;
            }
        }
        String ListName
        {
            get
            {
                return txtTargetList.Text;
            }
        }
        String FolderName
        {
            get
            {
                return txtTargetListFolder.Text;
            }
        }
        DateTime? ProcessStartDate
        {
            get { return _processStartDate; }
            set
            {
                _processStartDate = value;
                var invoker = new MethodInvoker(delegate
                {
                    if (_processStartDate.HasValue)
                    {
                        txtStartDateTime.Text = _processStartDate.Value.ToString(CommonConstants.DATE_FORMAT);
                    }
                    else
                    {
                        txtStartDateTime.ResetText();
                    }
                });

                if (txtStartDateTime.InvokeRequired)
                {
                    txtStartDateTime.Invoke(invoker);
                }
                else
                {
                    invoker.Invoke();
                }
            }
        }
        DateTime? ProcessEndDate
        {
            get { return _processEndDate; }
            set
            {
                _processEndDate = value;
                var invoker = new MethodInvoker(delegate
                {
                    if (_processEndDate.HasValue)
                    {
                        txtEndDateTime.Text = _processEndDate.Value.ToString(CommonConstants.DATE_FORMAT);
                    }
                    else
                    {
                        txtEndDateTime.ResetText();
                    }
                });
                if (txtEndDateTime.InvokeRequired)
                {
                    txtEndDateTime.Invoke(invoker);
                }
                else
                {
                    invoker.Invoke();
                }
            }
        }
        TimeSpan ProcessTimeSpan
        {
            get
            {
                if (ProcessEndDate.HasValue && ProcessStartDate.HasValue)
                {
                    return ProcessEndDate.Value.Subtract(ProcessStartDate.Value);
                }
                return new TimeSpan();
            }
        }
        TimeSpan ElapsedDateTime
        {
            set
            {
                var invoker = new MethodInvoker(delegate { txtElapsedDateTime.Text = String.Format("Process Execution. {0} Day(s) | {1} Hour(s) | {2} Minute(s) | {3} Second(s).", value.Days, value.Hours, value.Minutes, value.Seconds); });
                if (txtElapsedDateTime.InvokeRequired)
                {
                    txtElapsedDateTime.Invoke(invoker);
                }
                else
                {
                    invoker.Invoke();
                }
            }
        }
        int ExceptionCounter
        {
            get { return _exceptionCounter; }
            set
            {
                _exceptionCounter = value;
                var invoker = new MethodInvoker(delegate { txtExceptionsOccurred.Text = (String.Format("Exceptions Occurred: {0}", _exceptionCounter)); });
                if (txtExceptionsOccurred.InvokeRequired)
                {
                    txtExceptionsOccurred.Invoke(invoker);
                }
                else
                {
                    invoker.Invoke();
                }
            }
        }
        #endregion

        #region Private Fields
        private DateTime? _processStartDate = DateTime.Now;
        private DateTime? _processEndDate = DateTime.Now;
        private int _exceptionCounter;
        private int _totalRecords;
        #endregion
    }
}
